home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-06 | 59.6 KB | 1,256 lines |
-
- C MAGIC
- Version 1.5
-
- (c) Copyright 1992, Jeff Napier & Another Company
-
-
- Tutorial File
-
- What C Magic can do for you:
-
- This disk consists of three main parts, MAGIC.LIB,
- MAGIC.TXT and TUTOR.DOC. MAGIC.LIB is an add-in for
- Borland's Turbo C and BORLAND C products. It will work on
- versions from Turbo C 1.5 through Borland C++ version 3.1,
- and probably work on future versions as well.
-
- C MAGIC which will make your job as a programmer much
- easier and your results much more polished. MAGIC.TXT is a
- text file which explains how to use all the features of
- MAGIC.LIB, and TUTOR.DOC, the file you are now reading, is a
- tutorial which starts at a very beginning level and quickly,
- but effortlessly moves into advanced programming techniques.
-
- Specifically, MAGIC.LIB offers the following:
-
- * Automatic pop-up text boxes, dialog boxes and light-bar
- menus.
-
- * Automatic handling of text files.
-
- * Built-in mouse and cursor support for the programs you
- create.
-
- * Support for graphics programs to make them as easy to write
- as text-based programs. This includes a universal mouse
- cursor which will operate from the keyboard as well as from
- mouse movement whether or not a mouse is available.
-
- * Incorporation of .BGI and .CHR files directly into finished
- .EXE files.
-
- * Built-in 256-color VGA support. (Except with older versions
- of Turbo C.)
-
- * Sound effects for your programs.
-
- * Simplification of many standard C operations.
-
- * Complete color control in text and graphics modes.
-
- * Full, documented, easy-to-understand source code is
- available so you can learn from and customize the Magic
- framework to your own applications.
-
- * OOP supported but not required.
-
- NOTE:
-
- This is a shareware product. You have our permission to
- copy and distribute this package as long as all files remain
- intact and unchanged.
- If you benefit from this tutorial, or if you use the
- MAGIC.LIB unit in your programs you are expected to register.
- To register, send $39.95 to:
-
- Another Company
- P.O. Box 298
- Applegate, OR 97530
- USA
-
- Please add $3 per order for postage in the USA, $5 for
- postage to Canada, or $7 for postage to all other countries.
- Please add $1 if you require 3.5" disk size.
-
- If you would like the full source code sent with your
- registration, send $79.90 plus postage. Please add $2 if you
- require 3.5" disk size.
-
- QUESTIONS:
-
- If you have questions: 503-846-7884, 9-5 Weekdays, West Coast
- time. (We are not always available during those hours, but
- you can try.)
-
- THE BEST WAY TO USE THIS TUTORIAL:
-
- Copy MAGIC.LIB to the directory where you keep your .LIB
- files, copy MAGIC.H to the directory which contains your
- include (*.H) files, and copy TUTOR.DOC to the directory
- which contains your source code files. Start your BC.EXE or
- TC.EXE and load in this file (type: BC TUTOR.DOC). Since the
- IDE* (Integrated Development Environment) allows you to work
- on several files at once, you can read this tutorial in one
- window and work on practice programs in another window. If
- you don't know how yet, I'll show you. If you are an
- experienced programmer, you might want to skim through this
- tutorial and concentrate only on the areas that are new to
- you.
-
- * Some of the older versions of Turbo C do not have a
- multi-window IDE. With these versions, simply switch from
- one file to another as required.
-
- A COUPLE OF OTHER NOTES:
-
- 1. It is assumed that you have legally purchased a Borland C
- compiler and therefore have the valuable printed manuals that
- come with the kit. If not, you are advised to spend a little
- money and get what you need, because there are places within
- this tutorial which will refer you to those books to complete
- your knowledge.
-
- 2. This is not the last word on C. It doesn't teach
- everything about programming - probably not even 10 percent
- of what you will eventually learn, but between this tutorial
- and the Borland manuals, you'll get pretty good at
- programming, and fairly quickly. One of the best ways to
- learn this is to experiment frequently. Tear the example
- programs apart and try to interject your own ideas into them.
- See what you can change or improve, then run the programs you
- have modified and see what happens. As you well know, you
- can't hurt your computer by typing an incorrect line of code.
-
- 3. C is sensitive to capitalization. You must be careful to
- use capital letters and lower case letters in the right
- places. The exact placement of indentations is not important,
- however, and every programmer develops a slightly different
- style.
-
- 4. This is version 1.5 of what I believe is a good product,
- but then, I wrote it. Let me know what you think. I'm pretty
- sure I caught all the major bugs, but there may be some minor
- ones. Most likely the registered and/or subsequent shareware
- versions will be even better! Registered users always get
- the very latest version with whatever improvements have been
- added since the shareware release.
-
-
- HERE WE GO:
-
- Here is the simplest program you can write:
-
- main() {}
-
- Let's try it out. Press [F3]. (First finish reading this
- paragraph so you know how to get back.) A window pops up
- asking for a file name. Call it Prog1 (or any name you
- choose) and type the preceding one-line program. Press [F2]
- to save your valuable work against power failure, etc. While
- holding the [Ctrl] key, press [F9] and the program will run.
- (With older versions of Turbo C, hold [Alt] and press [r].)
- Did you blink? Since, the program doesn't actually do
- anything, it runs very quickly, then returns to the IDE.
-
- IDE stands for Integrated Development Environment, what
- Borland calls their compiler. We'll use the same name rather
- than trying to say Borland C, or something equally confusing.
-
- Let's look at the program you just ran in detail. Main()
- is a function. Every C program must have one main() function.
- This program was a very simple one, and so there are no
- additional details needed between the parentheses. They are
- there simply to tell the computer that "main" is a function,
- not a number or an instruction of some sort. The main()
- function starts after the curly bracket. It is there to tell
- the computer that this is where the function will begin. The
- closing curly bracket tells the computer that the function is
- done. Since there is nothing between the curly brackets, the
- program does nothing.
-
- If you are sharp, you may have noticed that the IDE issued
- a warning message. If you don't see it at the bottom of the
- screen, press [F6]. Technically, all functions give a
- response when they are run unless they are provided with the
- special word "void."
-
- So in the next program, we'll precede main() with void.
- Next, we'll add something to the program so it will actually
- have a purpose:
-
- void main(){
- printf("Hello, World!");
- }
-
- Go back to your program (hold [Alt] and press [1] or [2]),
- and modify it to imitate the above example. Hold [Ctrl] and
- press [F9] (or [Alt] + [r]) to run it.
- What happened? Well, it worked alright, but if you have
- a recent compiler, you did not see anything, because it
- happened very quickly and returned to the IDE when it was
- done. Let's add another function to slow it down. Getch()
- waits patiently for the user to press a key before the
- program continues, thereby giving you a chance to see "Hello,
- World!" written on the screen. Test this one out:
-
- void main(){
- printf("Hello, World!");
- getch();
- }
-
- If you have a recent Borland compiler, it issued two
- warnings! You see, the IDE doesn't trust you to use printf()
- or getch() properly. And that's a good thing, because when
- you start writing complicated programs, you'll need all the
- help you can get from the IDE. Any function that you try to
- use is checked to see that you are feeding it right
- information. In this case, printf() is a function which
- writes text onto the screen. You want printf() to write a
- literal string, "Hello, World!", but what if you accidentally
- told it to write 14 cucumbers. It wouldn't know what
- cucumbers are, or what to do with 14 of them. So C restricts
- you to passing information to functions that they can handle.
- To do this, you must list the functions that you are going to
- use and what kind of information they can handle, before you
- use them. A typical C program has a list of function
- "prototypes" and their acceptable "parameters" at the top of
- the program.
-
- Printf() and getch() are two of hundreds of functions
- provided with C in a separate disk file called a library.
- There are several such libraries available so you don't have
- to reinvent the wheel when you make your own programs. There
- are functions for dividing numbers, drawing circles, writing
- disk files, and so on.
-
- As a program grows in size, you may end up using a
- hundred or so of these functions. Rather than list them all
- at the top of your source code, you can "include" a header
- file. Borland provides several header files for the
- functions in their library files. The one which contains the
- prototypes for printf() and getch() is STDIO.H in older
- versions of Turbo C, or CONIO.H in new versions. Look at the
- following program listing to see how it is included:
-
- #include <stdio.h>
- void main(){
- printf("Hello, World!");
- getch();
- }
-
- While you are at it, look at STDIO.H or CONIO.H and look
- at the prototypes in the header file.
-
- Again, you can type in the changes and test this
- program. Or, you could save yourself a bit of work. If you
- have a mouse and a new version compiler:
-
- Move the cursor to the top of the program in this file.
- (Move it to the # in "#include." Then select the whole
- program by holding down the left mouse button and moving the
- mouse until the whole four lines change color. Then select
- Edit from the top menu and Copy. Then open a new window
- (press [F3]) and then select Paste from the Edit menu.
-
- Or from the keyboard: Move the cursor to the top of the
- program and hold [Ctrl] and press [k] then [b]. (This is
- referred to as ^kb.) Then, using the arrow keys move to the
- bottom of the program listing and press ^kk. Then [Alt] +
- [e],[c]. Open a new window (press [F3]) and then select
- [Alt] + [e] + [p].
-
- The program will be pasted in the new window. Save the
- program with a press of the [F2] key, then run it. (Hold
- [Ctrl] and press [F9])
-
- With the older compilers, you use ^kb and ^kk to mark a
- block, and then press ^kw to write a block. You'll be asked
- to name a file for the block so choose a name like "TEMP".
- A file called TEMP.C appears on your disk. Then move into
- another file, such as TEST.C, and press ^kr to "read" the
- block, TEMP.C into the file.
-
- If you haven't changed the layout of directories and
- files, the program will run just fine. If it can't find
- STDIO.H, select Options from the top menu, then Directories,
- then tell the IDE where it should look for "INCLUDE" files.
-
- Our little program works, but it doesn't look like much,
- does it? Here's a wonderful opportunity for me to show you
- how much better C Magic is. Let's try a variation of that
- program. But first, you'll need to do a couple of things,
- Copy MAGIC.LIB into the directory containing your *.LIB
- files, and MAGIC.H into the directory containing your other
- *.H files (general called the INCLUDE directory).
-
- In order to incorporate MAGIC.LIB into your programs,
- you'll need to start a "project". This is easier than it
- sounds. Simply choose Project from the top menu, then choose
- Open. Give it any DOS-legal name (up to 8 letters) which
- will end with .PRJ. Then Choose Include from the Project
- menu and type your program name, then MAGIC.LIB, and also
- GRAPHICS.LIB. Now all the functions within MAGIC.LIB will be
- available to your program.
-
- If you have an older version compiler, you make a .PRJ
- file by simply pressing [F3] to edit a new file, and name it
- something specifically ending with .PRJ. In this file, you
- type your program name (for instance, TEST.C), and then, on
- the next line, MAGIC.LIB, and on a third line, GRAPHICS.LIB.
-
- IMPORTANT NOTE:
-
- GRAPHICS.LIB is a library of graphics routines, some of
- which are used by MAGIC.LIB, even for non-graphics programs.
- Therefore, GRAPHICS.LIB must always be included along with
- MAGIC.LIB in your "projects."
-
- And now type or paste this into a file of it's own:
-
- #include <magic.h>
- void main(){
- xclear();
- pile("Hello, World!");
- getanykey(10,10);
- }
-
- This program should run, and look quite impressive
- compared to the earlier version.
-
- If You Have Problems:
-
- Select OPTIONS from the top menu, then COMPILER, then
- CODE GENERATION. The memory model MUST be LARGE. Magic will
- not work with smaller memory models.
-
- When you start a .PRJ file, the settings you may have
- selected from the OPTIONS menu may change. Especially check
- the Options | Directories menu.
-
- Another potential problem is that you can forget to use
- the graphics library, which must be linked with MAGIC even if
- you aren't using any graphics. This is because MAGIC is
- always READY for graphics. With Borland C++ version 3.0 or
- 3.1, select OPTIONS, then LINKER, then LIBRARIES, and make
- sure the box for GRAPHICS.LIB is checked. You can leave it
- checked for all programs you write, because it is only linked
- into programs which use it. The only difference is your
- programs will compile a bit slower. With the older versions,
- simply include the line GRAPHICS.LIB in your .PRJ files.
-
- While the above program is similar to the previous ones,
- you'll see some different functions.
-
- Since the above program uses functions from within
- MAGIC.LIB, we use the MAGIC.H header file to prototype the
- functions.
-
- The first one, xclear(), simply clears the previous junk
- off the screen. Then pile() gets the "Hello, World!" string.
- We'll talk more about pile() later. Finally, getanykey()
- places the "Hello, World!" string on the screen, but in a
- fancy box!
-
- Getanykey() gets two numbers, the coordinates at which
- the upper left corner of the pop-up box is to appear. The
- first number is the horizontal position. 1 is the extreme
- left edge of the screen and 80 is the right-most edge. The
- second number is the vertical position which can range from 1
- to almost 25. If you use a negative integer for one or both
- numbers, the box is automatically centered on the screen,
- horizontally, vertically, or both. Like getch(), getanykey()
- waits for the user to press any key. Unlike getch(), it then
- erases the text box from the screen. Also, it will respond
- to a mouse button. If the left button is clicked,
- getanykey() acts as if [Enter] was pressed and the right
- mouse button is equivalent to [Esc].
-
- Lets add a few things to the previous program:
-
- /* program #6 */
- #include <magic.h>
- void main(){
- magic_setup();
- xclear();
- pile("Do you want to quit? (Y/N)");
- pile("");
- pile("This is just an example. Actually, the");
- pile("program will quit whether you type Y or N");
- getyn(-1,-1);
- }
-
- The very top line, starting with /* and ending with */ is
- a comment. Comments have no effect on the program, and are
- available just for making notes. You can include comments
- just about anywhere, but there are two restrictions: You
- must have the /* marker at the beginning and the */ at the
- end; and you cannot usually include comments within comments.
- (Compilers which support C++ also accept // as the start of a
- comment and the end of a line as the end.)
-
- Using lots of comments is a good idea because they can
- help you think out a program that is giving you trouble. By
- adding comments, you can sometimes understand your code
- better. Also, they help you remember what you did last week
- or last year. They do not change the size of or slow down
- the finished .EXE file.
-
- We added a new function from the MAGIC library, this
- one, magic_setup(), seemingly does nothing. In fact, it does
- lots of stuff in the background, ranging from fixing up a
- sound effects error in older compilers to getting ready for
- graphics screens should you decide to use graphics. It is
- advisable, in fact necessary in most cases, to call
- magic_setup() once at the beginning of most programs which
- use the MAGIC library.
-
- You can see now that pile() builds a pile of strings of
- text for display. You can call pile() over and over again.
- Each time you do, another line is added to the "pile." The
- pile is actually a global array of 46 strings, called sent[],
- each up to 80 characters long.
-
- In this program, getanykey() has been replaced with
- getyn(), which waits until the user types [Y], [y], [N], [n],
- or clicks the left or right mouse button. (NOTE: The mouse
- is optional. It does not have to be hooked up.) When getyn()
- is done, it sets a global char variable called "u" to either
- capital "Y" or "N".
-
- Also, the coordinates have changed. Getyn() now uses two
- negative integers, and will therefore center itself on the
- screen.
-
- C mostly isn't sensitive to white space. You can organize
- the actual layout of your program differently. It is usually
- done with indentations similar to the examples you have been
- looking at. This makes the programs much easier to read and
- understand. To illustrate this point, look at program #6a,
- below, which compiles and runs just like program #6. You'll
- notice, however, that the "#include" is on its own line.
- Directives starting with # must be on their own line and the
- line must start with the #.
-
- /* program #6a */
- #include <magic.h>
- magic_setup(); void main(){xclear();
- pile("Do you want to quit? (Y/N)"); pile("");
- pile("This is just an example. Actually, the");
- pile("program will quit whether you type Y or N");
- getyn(-1,-1);}
-
- In the next program, I'll show how you'd actually use
- getyn().
-
- /* program #7 */
- #include <magic.h>
- void main(){
- magic_setup();
- xclear();
- do {
- pile("Do you want to quit? (Y/N)");
- pile("");
- pile("This version works like it should.");
- getyn(-1,-1);
- }
- while (u != 'Y');
- }
-
- Most of the program is the same. But look at the "do
- {" line. This starts a loop which executes over and over
- again until the condition following the "while" allows the
- program to "fall through" or continue past the loop. The
- curly bracket following the "do" and on the line before the
- "while" contain the statements which are allowed to repeat.
- "!=" is C talk for "not equal to." Remember that getyn()
- allows only [y], [Y], [n], or [N], or a mouse button, and
- returns the variable "u" only as (capital) [Y] or [N]. So,
- until the user answers "yes" with [Y] or [y] or the left
- mouse button, the computer is gonna keep asking "Do you want
- to quit," etc.
-
- You'll notice that the pile()s are repeated as well. This
- is because as soon as getyn() is done, it resets all the
- strings in the pile to blanks, in preparation for whatever
- the programmer might want next. For this loop to work right,
- you have to keep forcing the pile back to the strings you
- want displayed.
-
- In this next variation, there are two small changes to
- pretty it up:
-
-
- /* program #8 */
- #include <magic.h>
- void main(){
- magic_setup();
- xclear();
- centerjustify = 1;
- musicon = 0;
- do {
- pile("Do you want to quit? (Y/N)");
- pile("");
- pile("This version works like it should.");
- getyn(-1,-1);
- }
- while (u != 'Y');
- }
-
- First we have set a global variable called centerjustify
- to 1. When this is set, all the MAGIC functions which print
- the pile to the screen automatically center the strings of
- text within the pop-up box. If centerjustify were set to 0,
- the default condition, the strings are not centered.
-
- Then, another variable called musicon, which is 1 by
- default, has been set to 0, and now sound effects will not
- play when pop-up boxes appear and disappear. Using 1 and 0 is
- common practice in C programs. 1 is used to represent TRUE
- or ON or YES and 0 equals NO or OFF or FALSE.
-
- Compile and run program 8 and see if you like it better.
-
- Now, here's a little project: See if you can add another
- loop to program #8 which asks the user "Are you sure?" when
- "Do you want to quit?" is answered affirmatively.
-
- You might want to experiment a bit with this program,
- entering different messages, and different numbers of lines
- of text, and even lines of text of differing lengths.
-
- IMPORTANT NOTE:
-
- NOTE: There is a limit to the size of pop-up boxes. This
- limit depends on which graphics mode you are using. For
- instance, in VGA high-resolution, if you try to pop up a box
- containing more than about 20 lines of text, with the longest
- line being perhaps 40 characters long, you'll probably run
- out of RAM space. The result of this is a crash.
-
- This next program introduces another Magic function,
- dialog(), which also pops a text box onto the screen, but
- this box has a blank line at the bottom in which the user
- types a response. The answer is returned in a global variable
- called "answer."
-
- /* program #9 */
- #include <magic.h>
- void main(){
- magic_setup();
- xclear();
- pile("How would you answer this question?");
- dialog(-1,4);
- pile("User typed:");
- pile(answer);
- getanykey(-1,12);
- }
-
- Again, a good way to study this little program is to copy
- it into it's own window, try to guess what it does, then run
- it and see if it did what you expected.
-
- Notice the two lines "pile()ed" up for getanykey(). The
- first has a literal string surrounded by quotation marks.
- Nothing new about that. But the next call to pile() passes
- the variable, answer, not in quotation marks. If it were in
- quotation marks, the program would say:
-
- User typed:
- answer
-
- What you want instead is the value answer represents,
- which in this case is the string returned by dialog(). Answer
- is a global variable that always represents a string of zero
- or more characters.
-
-
- In program #9, you could make the whole operation more
- evident if you used some color control. Try program #10.
-
- /* program #10 */
- #include <magic.h>
- #include <conio.h>
- void main(){
- magic_setup();
- xclear();
- pile("How would you answer this question?");
- dialog(-1,4);
- boxback = WHITE;
- border = LIGHTBLUE;
- boxtext = BLACK;
- shadow = MAGENTA;
- mainback = RED;
- xclear();
- pile("User typed:");
- pile(answer);
- getanykey(-1,12);
- }
-
-
- Program 10 is ugly, but it shows you how to change the
- colors within the text box. The colors seem to be used here
- as some sort of variables and they are. They are defined in
- the CONIO.H file. (Use GRAPHICS.H if using older versions of
- Turbo C.) Boxback, boxtext, shadow, border, and mainback are
- global variables from Magic. These variables accept a number
- between 0 and 15. CONIO.H assigns BLACK to 0, BLUE to 1, and
- so on.
-
- If the program didn't work for you, make sure that you
- have "#include"d CONIO.H or GRAPHICS.H and that you have
- capitalized the color names, and used small letters for
- mainback, boxtext, etc..
-
- Mainback is the main background color, and will not
- change unless you call xclear() first to clear the screen and
- change the background color. There is another variable
- called maintext, for use when writing directly to the screen.
- Also available are bartext and barback for the highlight bar
- in menu(). (more about menu later)
-
- The colors could just as easily have been represented by
- numbers, as in the following example:
-
- /* program #11 */
- #include <magic.h>
- void main(){
- magic_setup();
- xclear();
- pile("How would you answer this question?");
- dialog(-1,4);
- boxback = 15;
- border = 9;
- boxtext = 0;
- shadow = 5;
- mainback = 4;
- xclear();
- pile("User typed:");
- pile(answer);
- getanykey(-1,12);
- }
-
- Notice that CONIO.H is not used in this program #11. It
- was only used to provide the defined colors which have been
- replaced with their normal numbers.
-
- With a bit of experimentation, you will soon discover
- that not all 16 colors are available in all situations. Only
- the first 8 are available for backgrounds, with the brighter
- colors reserved for text components. (In graphics modes, all
- 16 are available in all situations.)
-
- Let's find out what all the colors are: Here is a slightly
- more complex program than any we have made so far:
-
- /* program #12 */
- #include <magic.h>
- #include <conio.h>
- #include <stdlib.h>
- void main(){
- magic_setup();
- mainback = BLACK;
- xclear();
- border = WHITE;
- boxback = BLACK;
- centerjustify = 1;
- pile("Type a number from 0 to 15.");
- dialog(-1,-1);
- do {
- boxtext = atoi(answer);
- if ((boxtext < 1) || (boxtext > 15)) boxtext = 15;
- pile("The current color is");
- pile(answer);
- pile("Type a number from 0 to 15");
- pile("or press [Esc] to exit.");
- dialog(-1,-1);
- }
- while (u != 27);
- }
-
- Program 12 does this: First, the mainback, border color and
- the boxback color are changed and the screen is cleared.
- Because centerjustify is set to 1, it will cause text to be
- centered in the pop up boxes.
-
- Then a one-line dialog box appears. As soon as the user
- answers the question in this dialog box, a loop starts. The
- repeat loop changes the boxtext color to the corresponding to
- what the user typed in the dialog box. Since answer contains
- the ASCII (text) representation of what the user typed, it
- must be converted to the actual integer. This is done with
- atoi(). Atoi is prototyped in STDLIB.H, and this file is
- included at the top of the program.
-
- Since the only 'seeable' colors range from 1 to 15 (#0
- is BLACK), the line starting with 'if' repairs the boxtext
- number if it not suitable. Notice that it is a compound if.
- The || means "or." First, the whole expression evaluated by
- if is in parentheses, then each the expression on either side
- of the || is also in parentheses. At first, writing sensible
- statements containing || (or &&, meaning "and") can be
- difficult or confusing, but with practice, it all makes
- sense.
-
- Within the loop a new box pops up containing three lines
- of text written in the color corresponding to the number the
- user typed in the dialog box.
-
- This all repeats until the user presses [Esc], which, as
- you probably know is ASCII 27. You see, dialog() builds a
- string called answer. It uses the global variable u, a
- single character variable, to pick up each key the user
- presses, and this is why u is checked for the value of #27.
-
- Program 13 will be our first program that does something
- useful in the real world. It will produce the square of an
- integer. I know that's not much. You paid around $1000 for
- your computer, but your $5 calculator can do squares, and it
- can even do it with floating point numbers, which this
- example can't. The important thing is, once you learn this,
- you can build on this program.
-
- /* program #13 */
- #include <magic.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- void main(){
- int thing;
- char tempstr[80];
- magic_setup();
- xclear();
- do {
- pile("Type a number to be squared");
- pile("or press [Esc] to end program");
- dialog(-1,-1);
- if (u != 27) {
- thing = atoi(answer);
- thing *= thing;
- sprintf(answer,"%d",thing);
- strcpy(tempstr,"The square is ");
- strcat(tempstr,answer);
- pile(tempstr);
- getanykey(-1,-1);
- }
- }
- while (u != 27);
- }
-
- First, you'll notice we've included four header files.
- Each one contains prototypes for something in this program.
- Look at the line below main(). It merely declares "thing" a
- variable in which we can store an integer. Because thing
- is declared at the start of the main() function, it will be
- accessible throughout the program. Variables declared at the
- start of the main program are called "global." An "int" can
- hold a number between -32,768 and +32,767. If you are sharp,
- you can see a flaw in this program already. If the user types
- a number greater than 181, resulting in a square greater than
- 32,767, the program will not work properly. C offers many
- ways around this problem. For instance, instead of "int" we
- could use "long," a much bigger variable.
-
- The line below that declares "tempstr." This one is an
- array variable which can hold up to 80 characters - otherwise
- known as a "string." Allowing tempstr to be 80 characters
- long is overdoing it a bit, we could have used maybe 20 or
- so. In a very large program, you always want to keep your
- global variables small, but in a small program, it does not
- matter much.
-
- Then we have a typical do - while loop which repeatedly
- asks a question until the user presses [Esc] (ASCII 27). If
- the user does press [Esc] the block following the "if" does
- not execute. Otherwise, the string, answer, is converted to
- the integer, thing. Thing is squared, and the function()
- sprintf changes the new value of thing back into a string and
- the answer is displayed on the screen.
-
- Look carefully at the line: thing *= thing; If it doesn't
- make sense to you, that's because it is C shorthand. The same
- thing could be expressed as: thing = thing * thing. This
- shorthand can also be used with addition (thing += thing),
- subtraction and some other mathematical operations.
- There are a couple of new string handling techniques
- here. Sprintf() is a neat gadget which makes numbers of all
- sorts into strings, but requires some reading to understand
- fully. (look up sprintf() and printf() in your Borland
- manuals.) Strcat() combines two strings into one.
- Strcpy might come as a surprise to BASIC and PASCAL
- programmers. In C, because a string is not a special data
- type, but simply an array of characters, some things you
- might take for granted will not work. For instance, you
- cannot assign an variable number of characters to an array
- which might be a different size simply with an = sign. C does
- provide the library function strcpy() for that however.
-
- Here's another useful program:
-
- /* program #14 */
- #include <magic.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- void main(){
- float millimeters;
- char tempstr[80];
- magic_setup();
- xclear();
- do {
- pile("Enter a number of inches");
- pile("or press [Esc] when done");
- dialog(-1,3);
- if (u != 27) {
- millimeters = atoi(answer) * 25.4;
- sprintf(answer,"%f",millimeters);
- strcpy(tempstr,"That would be ");
- strcat(tempstr,answer);
- strcat(tempstr," millimeters.");
- pile(tempstr);
- getanykey(-1,16);
- } /* end of if block */
- } /* end of do block */
- while (u != 27);
- }
-
-
- You'll notice in the seventh line that were are declaring
- a variable of type "float." This means floating point and
- must be used because the result of multiplication by 25.4 is
- not usually going to be an integer. But this program looks a
- bit messy. What are all those digits doing in the answer?
- Lets fix it to truncate the answer to an integer:
-
- /* program #15 */
- #include <magic.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- void main(){
- float millimeters;
- char tempstr[80];
- magic_setup();
- xclear();
- do {
- pile("Enter a number of inches");
- pile("or press [Esc] when done");
- dialog(-1,3);
- if (u != 27) {
- millimeters = atof(answer) * 25.4;
- sprintf(answer,"%0.0f",millimeters);
- strcpy(tempstr,"That would be ");
- strcat(tempstr,answer);
- strcat(tempstr," millimeters.");
- pile(tempstr);
- getanykey(-1,16);
- } /* end of if block */
- } /* end of do block*/
- while (u != 27);
- }
-
- The trick is in the sprintf() line. This now has a width
- and precision specifier, and the program now truncates the
- answer to show an integer answer. There are several
- variations available in outputting strings representing
- numbers ranging from scientific notation to specific numbers
- of leading and trailing zeroes or significant digits. For
- more information, see your Borland Library Reference book.
- Look up printf() and sprintf().
-
- Program 16 converts Dupers from the imaginary country
- Xanopieland to United States Dollars.
-
- /* program #16 */
- #include <magic.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #define CONVERSION 0.7143
- void main(){
- float dollars;
- char tempstr[20];
- magic_setup();
- xclear();
- centerjustify = 1;
- strcpy(sent[1],"How many Dupers?");
- dialog(-1,-1);
- dollars = atof(answer) * CONVERSION;
- sprintf(tempstr,"%0.2f",dollars);
- strcat(sent[3],"$");
- strcat(sent[3],tempstr);
- strcpy(sent[1],"You own this much Xanopieland money:");
- /* notice that sent[3] is assigned above sent[1] */
- strcpy(sent[5],"Press any key to end program...");
- getanykey(-1,-1);
- }
-
- This program shows several new features. In the sixth
- line is "#define" which simply allows the programmer to type
- the CONVERSION anywhere in the program and the compiler will
- take it to mean 0.7143. This is very useful in large
- programs. Instead of trying to remember 0.7143 every time
- you need it, you can simply type CONVERSION in your source
- code. Also, let's say you revise the program next year when
- the conversion ratio advances to 0.7224. You simply change
- your code in one place, but the proper conversion occurs
- throughout your program. And, of course, it can be easier to
- understand complicated code when you have used clear meanings
- in your #defines.
-
- Look at the "How many Dupers?" line. Notice that instead
- of pile(), we used strcpy() and the variable "sent[1]." As
- you may remember, "sent" is a two dimensional array which is
- declared in the file MAGIC.H as "sent[46][81]". This allows
- you to make a pile() of up to 46 separate sent(ences) up to
- 80 characters long each. (C assigns an ASCII #0 to the end
- of character arrays, meaning you need room for one extra,
- hence the [81].)
-
- Pile() is nice because you don't have to keep track of
- which sent[] you are using, but sometimes manual control is
- useful.
-
- The sprintf() line uses a precision specifier to cause
- the output of the dollar amount to show two positions to the
- right of the decimal point. Nothing else would look sensible
- when converting to dollars and cents. Who ever heard of
- $12.3, or $12.3700000?
-
- And finally, you will see that the sent[]s are built up
- out of order. And why not? This could be easier for you,
- the programmer, but the final result will look the same.
- This is something you could not do if you used pile().
- Also, you'll notice that sent[2] and sent[4] are never
- affected. They started out as blank lines, and in this
- program we'll leave them that way.
-
- Let's make one more improvement. In program #17, we'll
- straighten out the way Dupers can be entered. The standard
- dialog box is as wide as the widest sent[] and therefore the
- answer can be that long. What if you want to limit the user
- to a 4-digit answer, for instance? The following technique
- also works well for use with filling in database forms:
-
- /* program #17 */
- #include <magic.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #define CONVERSION 0.7143
- void main(){
- float dollars;
- char tempstr[20];
- magic_setup();
- xclear();
- centerjustify = 1;
- strcpy(sent[1],"How many Dupers?");
- strcpy(sent[2]," ");
- pop(-1,-1);
- textcolor(boxtext);
- textbackground(boxback);
- xreadln(38,12,4);
- restore();
- dollars = atof(answer) * CONVERSION;
- sprintf(tempstr,"%0.2f",dollars);
- strcat(sent[3],"$");
- strcat(sent[3],tempstr);
- strcpy(sent[1],"You own this much Xanopieland money:");
- strcpy(sent[5],"Press any key to end program...");
- getanykey(-1,-1);
- }
-
-
- Can you spot the differences? This program does not
- depend on dialog(). Instead, we pop up a box with "pop(),"
- which is a simple function that remembers what's on the
- screen, then puts a box on the screen. Since pop() will use
- only as many sent[]s as have text, sent[2] is " ", or one
- blank, so it will be included in pop()'s box. This will give
- the user a line within the box on which to type the answer.
-
- Then the current text color and background color are set
- to the same as the colors within the box, so that xreadln(),
- will work in the proper colors. Xreadln() is like the gets()
- function, or the Turbo Pascal readln procedure, but with
- three differences. Xreadln() accepts mouse control (left
- mouse button is like pressing [Enter] and right button is
- like [Esc]), Xreadln() requires two integers to designate the
- screen coordinates at which it will echo the text typed by
- the user, and a third integer which limits how long a string
- the user is allowed to type.
-
- Dialog() knows when the user is done, and restores the
- screen and disappears, but pop() doesn't know what is wanted,
- so stays on the screen until a specific call to restore(),
- which wipes it out and replaces the previous screen image.
-
- Near the top of the program you may also note we've added
- "#include <conio.h>, the header file where names for colors
- are defined. (With older Turbo C compilers, replace CONIO.H
- with GRAPHICS.H.)
-
- Program #18 shows many new techniques. It is the
- Universal Money Converter. For simplicity, only the first
- menu entry has a a function installed. Run this program to
- see what it does, then study the source code to see how it
- does it. From a practical point of view, you can see that
- with modifications, this could be used for real money from
- real countries. For that matter, the same program could be
- modified for many purposes. How about a universal metric
- converter that converts lengths, weights, temperatures, etc?
-
- (NOTE: When I first roughed out this tutorial, I got to
- thinking about the previous sentence, and an idea was born.
- It is now complete and being distributed as shareware.
- Perhaps you've seen it, THE UNIVERSAL CONVERTER. This new
- program performs over 600 useful calculations and it makes
- extensive use of the Magic library!)
-
- /* program #18 */
- #include <magic.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #define CONVERSION 0.7143
- void xano(void); /*** 1 ***/
- float dollars;
- char tempstr[20];
- void main(){
- magic_setup();
- xclear();
- centerjustify = 1;
- pile("Universal Money Converter");
- pop(-1,2);
- clearsents(); /*** 2 ***/
- mc = 1; /*** 3 ***/
- do {
- pile("Xanopieland");
- pile("Braze Island");
- pile("Nomania");
- pile("Grazille");
- pile("Exit to Dos");
- menu(-1,-1); /*** 4 ***/
- if (u == 13) {
- if (mc == 1) xano(); /*** 5 ***/
- /* if (mc == 2) braze();
- if (mc == 3) nomania();
- if (mc == 4) Grazille(); *** 6 *** */
- }
- }
- while (!((u == 13) && (mc == 5))); /*** 7 ***/
- cleanup(); /*** 8 ***/
- }
-
- void xano(void){ /*** 9 ***/
- pile("How many Xanopieland Dupers?");
- pile(" "); //must be at least one char *** 10 ***
- pop(-1,-1);
- textcolor(boxtext);
- textbackground(boxback);
- xreadln(38,12,4);
- restore();
- dollars = atof(answer) * CONVERSION;
- sprintf(tempstr,"%0.2f",dollars);
- strcat(sent[3],"$");
- strcat(sent[3],tempstr);
- strcpy(sent[1],"You own this much Xanopieland money:");
- getanykey(-1,-1);
- } // end of xano function
-
- Well, I've got some explaining to do this time. I've
- marked the 10 changes in this program with comments so you
- can follow all this:
-
- The most noticeable change is the use of a sub-routine.
- For the first time you define your own function (other than
- main()). At Note One, we have the "declaration" of the
- xano() function. This prototype merely tells the compiler
- to expect the function and to know what information might be
- passed to/from it. In this case, nothing is passed to it, so
- the parentheses contain the word "void". Also, nothing will
- come from it, so it is also preceded by the word "void." By
- now, you've probably looked at a couple of header (.H) files
- and recognize function declarations. This one could also
- have been put in a header file, but there is no need, because
- there are no other parts of the program in other files that
- are going to use it.
-
- Later, in the body of the program the xano() function is
- "defined." So, to review, first we "declare" a function,
- later we "define" it.
-
- At Note 2, we've popped a box onto the screen. Remember,
- that pop() is less sophisticated than other functions such as
- getanykey() or dialog() which use it. These also clean
- themselves off the screen when they are done. Pop() does
- not. It leaves itself on the screen and leaves the sent[]s
- that were used, full of text. Clearsents() is a Magic
- function which restores all the sent[]s to empty strings so
- you can use them again without having old text pop up in your
- new boxes.
-
- We're about to use a lightbar menu. But before we do, at
- Note 3, we ought to decide which menu item will be
- highlighted when the menu first appears.
-
- At Note 4, we actually call the menu() function. It
- starts like pop(), but lights up the sent[] corresponding to
- the number "mc." Using the mouse or arrow keys, the user can
- select an item then press [Enter] or [Esc]. When that
- happens, the menu is done, and erases itself from the screen,
- leaving behind a value in "mc" related to the menu item which
- was highlighted when the user was done.
-
- And at Note 5, we have a series of "if"s. In this case,
- most of them are commented out, because we haven't actually
- built the whole program. But, if the user quits the menu()
- with 1 highlighted, then we do have function - xano().
-
- Notice that we use two equal signs when checking for
- equality. This is different than assigning a value to a
- variable with one equal sign. If we were to do this:
-
- if (mc = 2)
-
- mc would become 2, but with == we harmlessly check it.
-
- As I said, the other options are commented out (Note 6),
- but if the user selects menu item 1, then control of the
- program is given to the function xano().
-
- Skipping ahead to Note #9: It doesn't matter where in
- the source code xano() is defined, as long as it has been
- declared in advance. Some programmers will put some
- functions ahead of the main() function, and others will put
- it below. This seems unusual to Pascal programmers who must
- always list sub-routines above routines which call them.
-
- At Note 9, you'll see a new kind of comment. This is
- unique to C++, and will not work in standard C source code.
- If you have an older C compiler, change these to the normal
- kind of comments with /* and */. When the marker // occurs
- on a line, everything to the right of that marker will be
- ignored by the compiler.
-
- Now, back up to Note 7. What a weird statement! What
- we're doing here is repeating the whole menu sequence until
- the user has highlighted menu item 5 ("Exit to Dos") AND
- pressed [Enter]. C programmers do things like this - with
- cryptic uses of the ! (not) operator and nested parentheses.
- The best way to unravel a thing like this is to read it in
- the same sequence as the compiler. Expressions in the
- innermost parentheses are evaluated first. If you still find
- it hard to read, sometimes you can put extra spaces on the
- line to break the expression into bite-size groups, or even
- cut it up into several lines.
-
- And finally, at Note 8, we have a new function,
- cleanup(), which, much like it sounds, cleans everything up,
- freeing memory, clearing the screen and a few other chores.
- When cleanup() is done, it stops the program and returns the
- user to DOS.
-
- Program #19 adds a switch statement. This cleans up the
- multiple "if" statements, but has little overall effect on
- the program, other than simplicity in the source code.
- Notice the use of "break" after all but the last comparison
- in the switch. This allows us to exit the switch once a
- match has been found.
- Then we've added another switch statement, allowing the
- end user to press any key corresponding to the first letter
- of a menu item, thereby executing the menu choice with a
- single keystroke.
-
- /* program #19 */
- #include <magic.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #include <ctype.h>
- #define CONVERSION 0.7143
- void xano(void);
- float dollars;
- char tempstr[20];
- void main(){
- magic_setup();
- xclear();
- centerjustify = 1;
- pile("Universal Money Converter");
- pop(25,2);
- clearsents();
- mc = 1;
- do {
- pile("Xanopieland");
- pile("Braze Island");
- pile("Nomania");
- pile("Grazille");
- pile("Exit to Dos");
- menu(-1,-1);
- switch (toupper(u)) {
- case 'X' : xano(); u = 126; break;
- // case 'B' : braze(); u = 126; break;
- // case 'N' : nomania(); u = 126; break;
- // case 'G' : Grazille(); u = 126; break;
- case 'E' : mc = 5; u = 13;
- }
- if (u == 13) switch (mc) {
- case 1 : xano(); break;
- // case 2 : braze(); break;
- // case 3 : nomania(); break;
- // case 4 : Grazille();
- }
- }
- while (!((u == 13) && (mc == 5)));
- cleanup();
- }
-
- void xano(void){
- pile("How many Xanopieland Dupers?");
- pile(" "); //must be at least one char
- pop(-1,-1);
- textcolor(boxtext);
- textbackground(boxback);
- xreadln(38,12,4);
- restore();
- dollars = atof(answer) * CONVERSION;
- sprintf(tempstr,"%0.2f",dollars);
- strcat(sent[3],"$");
- strcat(sent[3],tempstr);
- strcpy(sent[1],"You own this much Xanopieland money:");
- getanykey(-1,-1);
- } // end of xano function
-
- You see, the whole block which calls pile() several
- times, then menu(), then asseses the user input, is repeated,
- because if the user presses any key except an arrow key, the
- menu considers itself done and disappears. As the program
- falls through, if the key the user pressed is not one
- examined by the switch statement, or [Enter], then the menu
- simply reappears, over and over again, until the user presses
- [Enter] or the first letter of something on the menu.
-
- Notice the new way of commenting out the non-existent
- functions.
-
- There are opportunities for bugs here. You want to make
- sure u == 13 (the [Enter] key) before allowing the first
- "switch" to execute, because otherwise, a function may run
- twice in a row if the user presses a character key, first
- when mc = whatever, then then when u = 'whatever'. Also make
- sure to put the second case characters in single quote marks.
- And last, notice the "toupper(u)." Without this the user
- would have to press the shift key to get the desired result.
- Toupper() converts whatever is in the variable u into a
- capital letter.
-
- THIS TUTORIAL IS CONTINUED IN THE FILE: TUTOR.2
-
- (This file is split into two parts in case you are using an
- older Turbo C compiler, which does not support files larger
- than 64k.)
-